package com.mybatis.jpa.statement.builder;

import com.mybatis.jpa.common.AssociationUtil;
import com.mybatis.jpa.common.PersistentUtil;
import com.mybatis.jpa.constant.ResultMapConstants;
import com.mybatis.jpa.meta.NestedMeta;
import com.mybatis.jpa.meta.PersistentMeta;
import com.mybatis.jpa.statement.MybatisStatementAdapter;
import com.mybatis.jpa.statement.SqlAssistant;
import org.apache.ibatis.executor.keygen.NoKeyGenerator;
import org.apache.ibatis.mapping.SqlCommandType;

import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

/**
 * @author xiaoh
 * @version [版本号, 2018/5/9 17:44]
 * @Description:
 * @versio 1.0
 * 陕西小伙伴网络科技有限公司
 * Copyright (c) 2017 All Rights Reserved.
 */
public class SelectNestedBuilder implements StatementBuildable{


    @Override
    public String buildSQL(PersistentMeta persistentMeta, Method method) {
        Class<?> resultType = persistentMeta.getType();
        List<NestedMeta> nestedInfo = new ArrayList<>();
        NestedMeta masterTableInfo = new NestedMeta();
        // 设置主表主键
        masterTableInfo.setTableName(persistentMeta.getTableName());
        masterTableInfo.setMappedName(persistentMeta.getPrimaryColumnMeta().getColumnName());
        nestedInfo.add(masterTableInfo);
        String  masterTablePK = persistentMeta.getPrimaryColumnMeta().getColumnName();
        List<Field> associationFields = AssociationUtil.getAssociationFields(resultType);
        if (!associationFields.isEmpty()) {
            for (Field field : associationFields) {
                // 如果包含one2one吧one2one添加到集合中
                if (field.isAnnotationPresent(OneToOne.class)) {
                    NestedMeta nestedMeta = new NestedMeta();
                    Class<?> javaType = field.getType();
                    // 获取one2one 表名字和 关联列名字
                    nestedMeta.setTableName(PersistentUtil.getTableName(javaType));
                    nestedMeta.setMappedName(AssociationUtil.getMappedName(field));
                    nestedMeta.setMasterFieldName(masterTablePK);
                    //如果有 JoinColumn 则使用JoinColumn配置
                    if(field.isAnnotationPresent(JoinColumn.class))
                    {
                        JoinColumn join = field.getAnnotation(JoinColumn.class);
                        nestedMeta.setMasterFieldName(join.name());
                        nestedMeta.setMappedName(join.referencedColumnName());
                    }
                    nestedInfo.add(nestedMeta);
                }
                if (field.isAnnotationPresent(OneToMany.class)) {
                    Type genericType = field.getGenericType();
                    NestedMeta nestedMeta = new NestedMeta();
                    nestedMeta.setMasterFieldName(masterTablePK);
                    if (genericType instanceof ParameterizedType) {
                        // 获取one2one 表名字和 关联列名字
                        ParameterizedType pt = (ParameterizedType) genericType;
                        Class<?> actualType = (Class<?>) pt.getActualTypeArguments()[0];
                        nestedMeta.setTableName(PersistentUtil.getTableName(actualType));
                        nestedMeta.setMappedName(AssociationUtil.getMappedName(field));
                        nestedInfo.add(nestedMeta);
                    }
                    //如果有 JoinColumn 则使用JoinColumn配置
                    if(field.isAnnotationPresent(JoinColumn.class))
                    {
                        JoinColumn join = field.getAnnotation(JoinColumn.class);
                        nestedMeta.setMasterFieldName(join.name());
                        nestedMeta.setMappedName(join.referencedColumnName());
                    }
                }
            }
        }
        StringBuilder columnName = new StringBuilder();
        StringBuilder fromName = new StringBuilder();
        // 获取主表的表名字和 主表主键
        String masterTableNameAlias = camelCaseName(persistentMeta.getTableName());

        String limitSql = " <if test=\"pageStart != -1 and pageSize !=-1 \" >  " +
                "        LIMIT  ${pageStart},${pageSize} " +
                "      </if>  ";
        for (int i = 0; i < nestedInfo.size(); i++) {
            NestedMeta nestedMeta1 = nestedInfo.get(i);
            String tableName = nestedMeta1.getTableName();
            // 获取表别名
            String tableNameAlias =camelCaseName(nestedMeta1.getTableName());
            String mappedName = nestedMeta1.getMappedName();
            // 拼接sql的字段  from 表名字&join 条件
            if(i==0){
                columnName.append(tableNameAlias+".*,");
                // 0为主表 主表 需要用子查询做过滤和limit
                fromName.append( " (SELECT * FROM " + tableName  + "  " + tableNameAlias +  " " +  SqlAssistant.builderModelWhere( persistentMeta,true) +  " @{orderBySql} " + limitSql + " )  " + tableNameAlias );

            }else if(i==nestedInfo.size()-1){
                columnName.append(tableNameAlias+".*");
                fromName.append(" JOIN "+tableName+" "+tableNameAlias+" ON "+masterTableNameAlias+"."+ nestedMeta1.getMasterFieldName()+" = "+tableNameAlias+"."+mappedName);
            }else{
                columnName.append(camelCaseName(nestedMeta1.getTableName())+".*,");
                fromName.append(" JOIN "+tableName+" "+tableNameAlias+" ON "+masterTableNameAlias+"."+ nestedMeta1.getMasterFieldName()+" = "+tableNameAlias+"."+mappedName);
            }
        }
        // 格式化sql
        return String.format("<script> SELECT %s FROM %s %s", columnName.toString(),fromName.toString(),"") ;
    }



    @Override
    public void  parseStatement(MybatisStatementAdapter adapter, PersistentMeta persistentMeta, Method method) {
        // 方法名
        adapter.setMethodName(method.getName());
        // 参数类型
        if (method.getParameterTypes().length > 0) {
            // Mybatis mapper 方法最多支持一个参数,先设置成Object.class,mybatis会在sql中解析
            adapter.setParameterTypeClass(Object.class);
        } else {
            adapter.setParameterTypeClass(void.class);
        }

        String masterTableNameAlias = camelCaseName(persistentMeta.getTableName());

        String orderBy = getOrderByInfo( adapter,  persistentMeta,  method);

        // sqlScript
        adapter.setSqlScript(buildSQL(persistentMeta, method).replace("@{orderBySql}",orderBy) + " " + orderBy + "</script>");

        // 返回值类型
        adapter.setResultType(persistentMeta.getType());
        adapter.setResultMapId(ResultMapConstants.DEFAULT_NAMESPACE + "." + persistentMeta.getEntityName());

        adapter.setSqlCommandType(SqlCommandType.SELECT);

        // 主键策略
        adapter.setKeyGenerator(new NoKeyGenerator());
        adapter.setKeyProperty(null);
        adapter.setKeyColumn(null);

        adapter.parseStatement();
    }


    public static  String camelCaseName(String underscoreName) {
        StringBuilder result = new StringBuilder();
        if (underscoreName != null && underscoreName.length() > 0) {
            boolean flag = false;
            for (int i = 0; i < underscoreName.length(); i++) {
                char ch = underscoreName.charAt(i);
                if ("_".charAt(0) == ch) {
                    flag = true;
                } else {
                    if (flag) {
                        result.append(Character.toUpperCase(ch));
                        flag = false;
                    } else {
                        result.append(ch);
                    }
                }
            }
        }
        return result.toString();
    }


    /**
     * 获取order by的info
     * @param adapter
     * @param persistentMeta
     * @param method
     * @return
     */
    public String getOrderByInfo(MybatisStatementAdapter adapter, PersistentMeta persistentMeta, Method method){
        return "";
    }

}
